﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using PJ.Business;
using Microsoft.Practices.Composite.Events;
using System.Collections.ObjectModel;
using System.Collections;

namespace PJ.Presentation
{
    public abstract class BusinessObjectListViewModel<TBusinessObjectModel> : BaseViewModel, IBusinessObjectListViewModel
        where TBusinessObjectModel : class, IBusinessObjectModel
    {
        #region Constructor

        protected BusinessObjectListViewModel(IView view, IEventAggregator aggregator,
            IBusinessObjectService service)
            : base(view, aggregator)
        {
            if (service == null)
                throw new ArgumentNullException("service");
            _Service = service;
            EventAggregator.GetEvent<ApplicationCloseEvent>().Subscribe(OnApplicationClose);
        }

        protected BusinessObjectListViewModel()
        {
        }

        #endregion


        #region Interface implementation

        public override void Dispose()
        {
            Persist();
            Service = null;
        }

        public abstract void InitializingNewItem(IBusinessObjectModel newItem);

        public IList Items
        {
            get
            {
                ObservableCollection<TBusinessObjectModel> items = (ObservableCollection<TBusinessObjectModel>)ThreadUnsafeGetValue(ItemsProperty);
                if (items == null)
                {
                    Items = items = new ObservableCollection<TBusinessObjectModel>();
                    items.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ItemsChanged);
                }
                return items;
            }
            set
            {
                ThreadUnsafeSetValue(ItemsProperty, value);
            }
        }

        /// <summary>
        /// Set a new list
        /// </summary>
        /// <param name="globalIdList">list of new object global ids</param>
        public virtual void SetValues(string[] globalIdList)
        {
            try
            {
                Persist();
                IList items = Items;
                items.Clear();
                if (globalIdList != null)
                {
                    IEnumerable list = Service.GetList(globalIdList, PJ.Data.GetDataMode.UseCache);
                    foreach (IBusinessObject obj in list)
                        items.Add(CreateNewItem(obj));
                }
                if (items.Count == 0)
                    SelectionChange(null);
                else
                    SelectionChange((IBusinessObjectModel)items[0]);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message + "\n" + e.StackTrace);
            }
        }

        /// <summary>
        /// Get the model list content
        /// </summary>
        /// <returns>List of object global ids</returns>
        public virtual IEnumerable<string> GetValues()
        {
            throw new NotImplementedException();
        }

        public abstract void SelectionChange(IBusinessObjectModel businessObject);

        #endregion

        #region Protected


        protected virtual void OnApplicationClose(bool cancel)
        {
            Dispose();
        }
        
        public void Persist()
        {
            foreach (IBusinessObjectModel item in Items)
                item.Persist();
        }

        public IBusinessObjectService Service
        {
            get
            {
                if (_Service == null)
                    throw new Exception("Service is not initialized");
                return _Service;
            }
            set
            {
                if (_Service != value)
                {
                    if (_Service != null)
                    {
                        if (value != null)
                            throw new Exception("Service is already initialized");
                        _Service.Dispose();
                    }
                    _Service = value;
                }
            }
        }



        protected abstract IBusinessObjectModel CreateNewItem(string globalId);

        protected abstract IBusinessObjectModel CreateNewItem(IBusinessObject obj);


        protected void OnItemAdd(TBusinessObjectModel item)
        {
        }

        protected void OnItemMove(int from, int to)
        {
        }

        protected void OnItemRemove(TBusinessObjectModel item)
        {
            Service.Delete(item.GlobalId);
        }

        #endregion

        #region Private

        private void ItemsChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                    foreach (TBusinessObjectModel item in e.NewItems)
                        OnItemAdd(item);
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Move:
                    OnItemMove(e.OldStartingIndex, e.NewStartingIndex);
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                    foreach (TBusinessObjectModel item in e.OldItems)
                        OnItemRemove(item);
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                    break;
                default:
                    break;
            }
        }


        #endregion

        #region Fields

        public static readonly DependencyProperty ItemsProperty =
            DependencyProperty.Register("Items", typeof(ObservableCollection<TBusinessObjectModel>), typeof(BusinessObjectListViewModel<TBusinessObjectModel>));

        private IBusinessObjectService _Service;

        #endregion
    }
}
